#include "otaupdatethread.h"
#include <QDateTime>
#include <QDate>
#include <QDebug>
#include "binfile.h"

OTAUpdateThread::OTAUpdateThread(QObject *parent)
    : QThread{parent}
{
    m_cnt = 0;
    m_serialSendDataArr.resize(OTA_PACK_LEN);

    m_bootVer = 0x03E9;
    m_OPFSN = 0;
}

OTAUpdateThread::~OTAUpdateThread()
{
    // 请求终止
    requestInterruption();
    quit();
    wait();
    qDebug() << "OTAUpdateThread stop";
}

void OTAUpdateThread::run()
{
    qDebug() << "OTAUpdateThread run";
    // 是否请求终止
    while (!isInterruptionRequested())
    {
        switch(m_updateStep)
        {
        case OTA::STEP_COMFIRM_VER:
            OTAComfirmVersionHandler();
            m_updateStep++;
            break;
        case OTA::STEP_DECRYPT_AUTH:
            m_updateStep++;
            OTADecryptAuthHandler();
            break;
        case OTA::STEP_DECRYPT_RET:
            m_updateStep++;
            OTADecryptReturnHandler();
            break;
        case OTA::STEP_UPDATE_MSG_APPVER:
            OTAUpdateMsgAppLenHandler();
            m_updateStep++;
            break;
        case OTA::STEP_UPDATE_MSG_OPLEN:
            OTAUpdateMsgOPLenHandler();
            m_updateStep++;
            break;
        case OTA::STEP_UPDATE_MSG_OP:
            OTAUpdateMsgOPHandler();
            m_updateStep++;
            break;
        case OTA::STEP_APP_LEN:
            OTAAppBinLenHandler();
            m_updateStep++;
            break;
        case OTA::STEP_APP_BIN:
            OTAAppBinHandler();
            m_updateStep++;
            break;
        case OTA::STEP_CRC_4K:
            OTA4KCRCHandler();
            m_updateStep++;
            break;
        case OTA::STEP_CRC_ALL:
            OTACRCAllHandler();
            m_updateStep++;
            break;
        case OTA::STEP_JUMP_APP:
            OTAJumpAppHandler();
            m_updateStep++;
            break;
        }
    }
}

QByteArray OTAUpdateThread::readAll()
{
    return m_serialSendDataArr;
}


void OTAUpdateThread::OTAComfirmVersionHandler()
{
    QByteArray Arr(OTA_PACK_LEN,0);
    createHostPackage(Arr, 0x04, OTA::FUNC_COMFIRM_VER);
    Arr[4] = ++m_cnt;
    Arr[5] = 0x00;
    Arr[6] = 0x01;
    // 发送
    emit OTASerialSendData(Arr);
}

void OTAUpdateThread::OTAComfirmVersionResponse(QByteArray &data)
{
    if(data.size() < 8)
    {
        return;
    }
    quint16 soft = (quint16)(data.at(4) << 8) + (quint8)data.at(5);
    if(m_appVer != soft)
    {
        QString str = QString("软件版本不一致: 当前版本：%1, bin 版本：%2")
                          .arg(soft).arg(m_appVer);
        emit OTALog(str);
        if(OTA::STEP_COMFIRM_VER_CHECK == m_updateStep)
        {
            m_updateStep++;
        }
    }
    else
    {
        QString str = QString("版本一致(%1)，无需更新")
                          .arg(soft);
        emit OTALog(str);
    }
}

void OTAUpdateThread::OTADecryptAuthHandler()
{
    QByteArray Arr(OTA_PACK_LEN,0);
    createHostPackage(Arr);
    Arr[2] = 0x04; // 长度
    Arr[3] = OTA::FUNC_DECRYPT_AUTH;  // 功能码
    Arr[4] = 0x00;
    Arr[5] = 0x00;
    Arr[6] = 0x01;
    // 发送
    emit OTASerialSendData(Arr);
}

void OTAUpdateThread::OTADecryptAuthResponse(QByteArray &data)
{
    if(data.size() < 8)
    {
        return;
    }

    QByteArray zero_arr(7,0);
    qsizetype idx = data.indexOf(zero_arr);
    if(idx == 1)
    {  //全为零
        emit OTALog(QString("已认证"));
        if(OTA::STEP_DECRYPT_AUTH_CHECK == m_updateStep)
        {
            m_updateStep = OTA::STEP_UPDATE_MSG_APPVER;
        }
        return;
    }

    for(quint8 i = 0; i < 4; i++)
    {
        m_random_code[i] = data.at(i+2);
    }

    // 组成新的随机数
    quint8 M1 = ((m_random_code[1] & 0x0f) << 4) +
                ((m_random_code[0] & 0xf0) >> 4);
    quint8 M2 = ((m_random_code[2] & 0x0f) << 4) +
                ((m_random_code[3] & 0xf0) >> 4);

    quint8 pw2[] = decrypt_passwd_2;

    // 认证码
    quint8 auth1 = M1 ^ pw2[0];
    quint8 auth2 = M2 ^ pw2[1];

    if(auth1 == (quint8)data.at(6) && auth2 == (quint8)data.at(7))
    { // 认证成功
        emit OTALog(QString("认证成功"));
        if(OTA::STEP_DECRYPT_AUTH_CHECK == m_updateStep)
        {
            m_updateStep++;
        }
    }
    else
    {
        QString str = QString("认证失败：%1,auth1:%2, auth2:%3")
                          .arg(QString::number(data.at(1)))
                          .arg(QString::number(auth1))
                          .arg(QString::number(auth2));
        emit OTALog(str);
    }
}

void OTAUpdateThread::OTADecryptReturnHandler()
{
    QByteArray Arr(OTA_PACK_LEN,0);
    createHostPackage(Arr, 0x08, OTA::FUNC_DECRYPT_RET);
    Arr[4] = 0x01;

    quint8 pw6[] = decrypt_passwd_6;

    quint8 ret[6];
    quint32 sum = 0;
    quint32 pro = 1; // 积
    for(quint8 i = 0; i < 4; i++)
    {
        sum += m_random_code[i];
        pro *= m_random_code[i];
    }

    // 求出反转后的数据
    ret[0] = m_random_code[3] ;
    ret[1] = sum;
    ret[2] = pro;
    ret[3] = m_random_code[0] ;
    ret[4] = m_random_code[1] ;
    ret[5] = m_random_code[2] ;

    // XOR
    for(uint8_t i = 0; i < 6; i++)
    {
        ret[i] ^= pw6[i];
        Arr[i+5] = ret[i];
    }

    // 发送
    emit OTASerialSendData(Arr);
}

void OTAUpdateThread::OTADecryptReturnResponse(QByteArray &data)
{
    if(data.size() < 2)
    {
        return;
    }

    if(!data.at(1))
    {//解密成功
        emit OTALog(QString("解密成功"));
        if(OTA::STEP_DECRYPT_RET_CHECK == m_updateStep)
        {
            m_updateStep++;
        }
    }
    else
    {
        QString str = QString("解密失败：%1").arg((quint8)data.at(1));
        emit OTALog(str);
    }
}

void OTAUpdateThread::OTAUpdateMsgAppLenHandler()
{
    QByteArray Arr(OTA_PACK_LEN,0);
    createHostPackage(Arr, 0x08, OTA::FUNC_UPDATE_MSG);
    Arr[4] = 0x01; // APP LEN
    Arr[5] = m_appVer >> 8;
    Arr[6] = m_appVer & 0xff;

    quint32 timestamp = QDateTime::currentMSecsSinceEpoch() / 1000;
    for(quint8 i = 0; i < 4; i++)
    {
        Arr[i+7] = timestamp >> ((3 - i) * 8);
    }

    // 发送
    emit OTASerialSendData(Arr);
}

void OTAUpdateThread::OTAUpdateMsgOPLenHandler()
{
    QByteArray Arr(OTA_PACK_LEN,0);
    createHostPackage(Arr, 0x04, OTA::FUNC_UPDATE_MSG);
    Arr[4] = 0x02; // 表示 OP LEN
    Arr[5] = 0x00;
    Arr[6] = m_operatorMsg.size(); // 操作员长度

    // 发送
    emit OTASerialSendData(Arr);
}

void OTAUpdateThread::OTAUpdateMsgOPHandler()
{
    QByteArray Arr(OTA_PACK_LEN,0);
    qsizetype size = (m_operatorMsg.size() > 5 ? 5 : m_operatorMsg.size());
    createHostPackage(Arr, size+3, OTA::FUNC_UPDATE_MSG);
    Arr[4] = 0x03; // 表示 OP
    Arr[5] = ++m_OPFSN; // 帧序号
    for(qsizetype i = 0; i < size; i++)
    {
        Arr[i+6] = m_operatorMsg.at(i);
    }
    // 删除已发送的信息
    m_operatorMsg.remove(0,size);

    // 发送
    emit OTASerialSendData(Arr);
}

void OTAUpdateThread::OTAUpdateMsgResponse(QByteArray &data)
{
    switch((std::uint8_t)data.at(1))
    {
    case 0x01:  //发送更新APP版本和时间戳
    case 0x02: // 发送操作员信息  长度
        if(!data.at(2))
        {
            if(OTA::STEP_UPDATE_MSG_APPVER_CHECK == m_updateStep ||
                OTA::STEP_UPDATE_MSG_OPLEN_CHECK == m_updateStep)
            {
                m_updateStep++;
            }
        }
        else
        {
            QString str = QString("更新信息失败：%1").arg((quint8)data.at(2));
            emit OTALog(str);
        }
        break;
    case 0x03:  // 发送操作员信息
        if(!data.at(2))
        {
            emit OTALog("操作员信息发送成功");
            if(!m_operatorMsg.size())
            {
                m_updateStep++;
            }
            else
            {
                m_updateStep--;  // 回去接着发
            }
        }
        else
        {
            QString str = QString("发送操作员信息失败：%1").arg((quint8)data.at(2));
            emit OTALog(str);
        }
        break;
    }
}

void OTAUpdateThread::OTAAppBinLenHandler()
{
    // 计算此次长度
    if(!AppBinBlockBegin())
    {
        QByteArray Arr(OTA_PACK_LEN,0);
        createHostPackage(Arr, 0x04, OTA::FUNC_APP_LEN);
        Arr[4] = m_BinBL; // 表示 APP 块序号

        Arr[5] = ((m_BinBLLen >> 8) & 0xff);
        Arr[6] = m_BinBLLen & 0xff; // 块 bin 长度

        // 发送
        emit OTASerialSendData(Arr);
    }
    else
    {
        emit OTALog("bin 无内容发送");
    }
}

void OTAUpdateThread::OTAAppBinLenResponse(QByteArray &data)
{
    if(!data.at(2))
    {
        if(OTA::STEP_APP_LEN_CHECK == m_updateStep)
        {
            QString str = QString("块(%1)总长度(%2)已发送")
                              .arg(QByteArray::number(data.at(1)))
                              .arg(m_Bin.size());
            emit OTALog(str);
            m_updateStep++;
        }
    }
    else
    {
        QString str = QString("块(%1)长度发送失败：%2")
                          .arg((quint8)data.at(1))
                          .arg((quint8)data.at(2));
        emit OTALog(str);
    }
}

void OTAUpdateThread::OTAAppBinHandler()
{
    QByteArray Arr(OTA_PACK_LEN,0);
    qsizetype len = m_BinBLLen - m_BinFSN * 6; // 一帧能发6字节，计算剩多少
    qsizetype size = (len <= 6 ? len : 6);
     // 加上帧序号和头
    createHostPackage(Arr, size+2, OTA::FUNC_APP_BIN);

    Arr[4] = m_BinFSN;
    for(qsizetype i = 0; i < size; i++)
    {
        Arr[i+5] = m_Bin.at(i);
    }
    // 删除已发送的信息
    m_Bin.remove(0,size);
    emit OTASetBlock(m_BinBL, m_BinFSN);

    // 发送
    emit OTASerialSendData(Arr);
}

void OTAUpdateThread::OTAAppBinResponse(QByteArray &data)
{
    if(!data.at(2))
    {
        QString str = QString("bin 发送(%1)块(%2)帧成功")
                          .arg(m_BinBL)
                          .arg(m_BinFSN);
        emit OTALog(str);
        if(!m_Bin.size())
        {
            // 1块发完了，跳到验证。
            m_updateStep = OTA::STEP_CRC_4K;
        }
        else
        {
            m_BinFSN++; // 帧序号增加
            m_updateStep--;  // 回去接着发
        }
    }
    else
    {
        QString str = QString("bin发送失败：%1").arg((quint8)data.at(2));
        emit OTALog(str);
    }
}

qsizetype OTAUpdateThread::AppBinBlockBegin()
{
    qsizetype len = m_BinLen - m_BinBL*BLOCK_LEN;
    if(len > 0)
    {
        m_BinBLLen = len <= BLOCK_LEN ? len: BLOCK_LEN;
        // 更新这一k BIN准备发送
        m_Bin = BinFile::getBinFileMid(m_BinBL*BLOCK_LEN,m_BinBLLen);
        m_4ksum = sumCheckOnly(m_Bin);
        m_4kcrc32 = CRC32Only(m_Bin);
        QString str1 = QString("%1").arg(m_4ksum,4,16,QLatin1Char('0')).toUpper();//不足1位补0
        QString str2 = QString("%1").arg(m_4kcrc32,8,16,QLatin1Char('0')).toUpper();//不足8位补0
        qDebug() <<"BL:" << m_BinBL << "4k_sum:"<< str1 << "4k_crc:"<< str2;
        if(m_Bin.size())
        {
            m_BinFSN = 0;
            return 0;
        }
    }
    return -1;
}

void OTAUpdateThread::OTA4KCRCHandler()
{
    QByteArray Arr(OTA_PACK_LEN,0);
    createHostPackage(Arr, 0x08, OTA::FUNC_CRC_4K);
    Arr[4] = m_BinBL; // 块编号

    Arr[5] = (m_4ksum >> 8) & 0xff;
    Arr[6] = m_4ksum & 0xff;

    Arr[7] = (m_4kcrc32 >> 24)& 0xff;
    Arr[8] = (m_4kcrc32 >> 16)& 0xff;
    Arr[9] = (m_4kcrc32 >> 8)& 0xff;
    Arr[10] = (m_4kcrc32)& 0xff;
    // 发送
    emit OTASerialSendData(Arr);
}

void OTAUpdateThread::OTA4KCRCResponse(QByteArray &data)
{
    if(!data.at(2))
    {
        QString str = QString("bin块(%1)校验成功")
                          .arg(m_BinBL);
        emit OTALog(str);
        if(++m_BinBL == m_BinAllBL)
        {
            // 校验一整文件
            m_updateStep = OTA::STEP_CRC_ALL;
        }
        else
        {
            //块偏移
            m_updateStep =  OTA::STEP_APP_LEN; // 重新发送
        }
    }
    else
    {
        QString str = QString("块(%1)校验失败：%2")
                          .arg(m_BinBL)
                          .arg((quint8)data.at(2));
        emit OTALog(str);
    }
}

void OTAUpdateThread::OTACRCAllHandler()
{
    QByteArray Arr(OTA_PACK_LEN,0);
    createHostPackage(Arr, 0x08, OTA::FUNC_CRC_ALL);

    Arr[4] = 0xFF; //

    QByteArray file = BinFile::getFileArr();
    quint16 sum = sumCheckOnly(file);
    quint32 crc32 = CRC32Only(file);

    Arr[5] = (sum >> 8) & 0xff;
    Arr[6] = sum & 0xff;

    Arr[7] = (crc32 >> 24)& 0xff;
    Arr[8] = (crc32 >> 16)& 0xff;
    Arr[9] = (crc32 >> 8)& 0xff;
    Arr[10] = (crc32)& 0xff;
    // 发送
    emit OTASerialSendData(Arr);
}

void OTAUpdateThread::OTACRCAllResponse(QByteArray &data)
{
    if(!data.at(2))
    {
        emit OTALog("全文件校验校验成功");
        m_updateStep++; //
    }
    else
    {
        QString str = QString("全文件校验失败：%1")
                          .arg((quint8)data.at(2));
        emit OTALog(str);
    }
}

void OTAUpdateThread::OTAJumpAppHandler()
{
    QByteArray Arr(OTA_PACK_LEN,0);
    createHostPackage(Arr, 0x04, OTA::FUNC_JUMP_APP);
    Arr[4] = 0x0A;
    Arr[5] = 0x00;
    Arr[6] = 0x01;
    // 发送
    emit OTASerialSendData(Arr);
}

void OTAUpdateThread::OTAJumpAppResponse(QByteArray &data)
{
    if(!data.at(2))
    {
        emit OTALog("更新完成！");
        m_updateStep++; //
    }
    else
    {
        QString str = QString("跳转APP失败：%1")
                          .arg((quint8)data.at(2));
        emit OTALog(str);
    }
}

void OTAUpdateThread::onOTADataReadySlot(QByteArray data)
{
    // qDebug()<< "OTADataReady:" << data.toHex();
    switch((std::uint8_t)data.at(0))
    {
    case OTA::FUNC_COMFIRM_VER: //确认版本
        OTAComfirmVersionResponse(data);
        break;
    case OTA::FUNC_DECRYPT_AUTH:
        OTADecryptAuthResponse(data);
        break;
    case OTA::FUNC_DECRYPT_RET:
        OTADecryptReturnResponse(data);
        break;
    case OTA::FUNC_UPDATE_MSG:
        OTAUpdateMsgResponse(data);
        break;
    case OTA::FUNC_APP_LEN:
        OTAAppBinLenResponse(data);
        break;
    case OTA::FUNC_APP_BIN:
        OTAAppBinResponse(data);
        break;
    case OTA::FUNC_CRC_4K:
        OTA4KCRCResponse(data);
        break;
    case OTA::FUNC_CRC_ALL:
        OTACRCAllResponse(data);
        break;
    case OTA::FUNC_JUMP_APP:
        OTAJumpAppResponse(data);
        break;
    case OTA::FUNC_TERMINATE:
        break;
    default:
        break;
    }
}

void OTAUpdateThread::onOTAUpdateStartSlot()
{
    this->start();
    m_isStop = 0;
    m_updateStep =  OTA::STEP_COMFIRM_VER; // 从确认版本开始
    m_appVer = BinFile::getAppVer();
    m_operatorMsg = BinFile::getOperatorMsg();
    m_BinLen = BinFile::getRdFileLen();
    m_BinBL = 0;
    m_OPFSN = 0;
    m_BinFSN = 0;

    m_BinAllBL = m_BinLen / BLOCK_LEN + (m_BinLen % BLOCK_LEN == 0? 0 : 1);
    emit OTASetAllBlock(m_BinAllBL);
    emit OTALog(QString("OTA Update Start"));
}

void OTAUpdateThread::onOTAUpdateStopSlot()
{
    m_isStop = 1;
    // 请求终止
    requestInterruption();
}



